feat: add support openai/privacy-filter model#1104
Merged
Conversation
chmjkb
reviewed
Apr 28, 2026
Collaborator
chmjkb
left a comment
There was a problem hiding this comment.
im not sure itf its good time to review this as this is a draft 😅
but I only noticed after starting the review so heres a couple of omments
01b99fe to
a0e04b4
Compare
Adds a new PrivacyFilter native model with TS hook, module, types and
demo screen, plus the openai/privacy-filter and OpenMed/privacy-filter
nemotron presets. Uses constrained Viterbi decoding with tunable BIOES
transition biases (matching openai's viterbi_calibration.json schema),
sliding 256-token windows with 50% overlap for arbitrary-length input,
and exposes results as a typed PiiEntity[] via a getJsiValue overload.
seq_len is read from the forward method's input shape so the same
runner works with any single-method privacy-filter export. Viterbi
decoder is split into its own module (Viterbi.{h,cpp}) following the
peer Utils.{h,cpp} convention.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
a0e04b4 to
02e13da
Compare
msluszniak
reviewed
Apr 30, 2026
Member
|
FYI, I tested demo apps and they worked correctly :)) |
- Strip personal appleTeamId from apps/llm/app.json - Use std::cmp_greater_equal for the labelId bounds check - Take padded buffers by non-const ref in runWindow so make_tensor_ptr no longer needs const_cast on the data pointers - Move the validLen <= 0 early-return above the forward call so we don't run inference on empty windows - Replace the trusted-slice write loop with std::copy - Drop redundant parens around isFirst / isLast - emplace_back the merged spans - Drop the redundant "decoded = """ inside the catch block (decoded is already default-constructed empty) - Use std::ranges::find_if + reverse iterator for the trim block, emplace_back the resulting PiiEntity - Use std::ranges::max_element for the Viterbi best-end search and drop the now-unused bestScore variable Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
msluszniak
reviewed
Apr 30, 2026
Member
msluszniak
left a comment
There was a problem hiding this comment.
Second pass — a few correctness issues + polish.
- Throw on wrong-sized viterbiBiases (size != 0 && size != 6) instead of silently falling through to defaults - Validate labelNames_[0] == "O" to match what the error message claims - Reject seq_len < 2 in the constructor (would otherwise make the sliding-window stride 0 and loop forever) - Comment Viterbi bp's unused first row (row 0 is allocated for index convenience; traceback starts at t = 1) - Drop hardcoded 256/128 magic numbers from the public JSDoc and the hook/module docs — restate as "50% overlap, window from forward input shape" so a future seq_len change doesn't drift the docs - Word-boundary-anchored regex in piiMatching to avoid "John" matching inside "Johnson" - Simplify the demo's run-error handler to the one-liner the hook's RnExecutorchError already supports Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds a new Privacy Filter native model for on-device PII detection, with a TypeScript hook (
usePrivacyFilter), module (PrivacyFilterModule), types, and a demo screen in theapps/llmexample. Two models are wired up out-of-the-box:PRIVACY_FILTER_OPENAI— openai/privacy-filter, 8 categories (person, email, phone, address, DOB, URL, account number, secret).PRIVACY_FILTER_NEMOTRON— OpenMed/privacy-filter-nemotron-base, 55+ categories adding medical, financial, demographic, technical, and government-document spans.Both models share the same single-method
forward(input_ids, attention_mask) → logitsgraph, the same o200k tokenizer (pad/eos id 199999), and 256-token banded attention. They differ only in the BIOES label space, which is supplied aslabelNamesat load time.Highlights:
viterbi_calibration.jsonschema. Defaults to neutral validity-only Viterbi.seq_lenis read from the model'sforwardinput shape at load time, so a 512-token export would Just Work without code changes.generate()returnsPiiEntity[]directly via agetJsiValueoverload — no JSON bridge.Viterbi.{h,cpp}module underrnexecutorch::models::privacy_filter::viterbi, mirroring theUtils.{h,cpp}convention used by VAD.Introduces a breaking change?
Type of change
Tested on
Testing instructions
cd apps/llm && yarn installyarn pods && yarn ios· Android:yarn androidScreenshots
Related issues
Checklist
Additional notes
tokenizer.jsonis bit-identical between the OpenAI base and the Nemotron fine-tune; both use the GPT-4oo200kBPE.forwardmethod rather than the 18-method multimethod export — this brings RAM down from ~3.5 GB to ~1.2 GB on iPhone 16 Pro and inference from ~8s to ~1.5s, since planner buffers are reused across the full graph.docs/docs/(next-version only). The06-api-reference/typedoc output regenerates automatically from the@category Models - Privacy Filtertags on the exported constants and the public hook/module/types — no manual entries were added there.02-benchmarks/) are intentionally not updated in this PR; we'll add measured numbers in a follow-up once we have proper multi-device timings.